﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace vlcplay.Logging
{
    public class FileLogger : ILogger
    {
        private readonly string _name;
        private readonly string _logDirectory;
        private readonly Func<string, LogLevel, bool> _filter;

        public FileLogger(string name, string logDirectory, Func<string, LogLevel, bool> filter)
        {
            _name = name;
            _logDirectory = logDirectory;
            _filter = filter ?? ((category, level) => true);
        }

        public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;

        public bool IsEnabled(LogLevel logLevel) => true;

        public void Log<TState>(
            LogLevel logLevel,
            EventId eventId,
            TState state,
            Exception? exception,
            Func<TState, Exception?, string> formatter)
        {
            if (!IsEnabled(logLevel))
            {
                return;
            }

            var message = formatter(state, exception);

            if (string.IsNullOrEmpty(message))
            {
                return;
            }

            var (className, _) = GetCallingLocation();
            // 只取日志级别前4个字符
            var levelShort = logLevel.ToString().Substring(0, Math.Min(4, logLevel.ToString().Length));
            var formattedMessage = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [{className}] [{levelShort}] {message}";

            if (exception != null)
            {
                formattedMessage += $"\n{exception}";
            }

            var logFile = Path.Combine(_logDirectory, $"log_{DateTime.Now:yyyyMMdd}.log");

            try
            {
                File.AppendAllText(logFile, formattedMessage + Environment.NewLine);
            }
            catch
            {
                // 忽略写入失败的情况
            }
        }

        private (string ClassName, int LineNumber) GetCallingLocation()
        {
            var stackTrace = new System.Diagnostics.StackTrace(true);
            foreach (var frame in stackTrace.GetFrames())
            {
                var method = frame.GetMethod();
                var declaringType = method?.DeclaringType; // method can be null
                if (declaringType == null) continue;
                var ns = declaringType.Namespace ?? "";
                // 跳过 Microsoft.Extensions.Logging 相关和 FileLogger
                if (!ns.StartsWith("Microsoft.Extensions.Logging") && (declaringType.FullName != null && !declaringType.FullName.Contains("FileLogger")))
                { // declaringType.FullName can be null if declaringType is an open generic type or an array type of an open generic type.
                    string className = declaringType.Name ?? "UnknownClass";
                    int line = frame.GetFileLineNumber();
                    if (line == 0) line = frame.GetILOffset();
                    return (className, line);
                }
            }
            return (_name, 0); // fallback to category name
        }


    }
}
